package org.go.scheduler.database;

import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.go.Go;
import org.go.expcetion.SchedulerException;
import org.go.trigger.Trigger;
import org.go.work.WorkRunShell;

/**
 * <p>
 * An extension of <code>{@link org.quartz.core.JobRunShell}</code> that
 * begins an XA transaction before executing the Job, and commits (or
 * rolls-back) the transaction after execution completes.
 * </p>
 * 
 * @see org.quartz.core.JobRunShell
 * 
 * @author James House
 */
public class JTAJobRunShell extends WorkRunShell {
	private static final org.go.log.Log log = org.go.log.LoggerFactory.getLog(JTAJobRunShell.class);

	private UserTransaction ut;

	public JTAJobRunShell(Go go, Trigger trigger) throws Exception {
		super(go, trigger);
		// TODO Auto-generated constructor stub
	}

	/**
	 * <p>
	 * Create a JTAJobRunShell instance with the given settings.
	 * </p>
	 */
	//	public JTAJobRunShell(Scheduler scheduler, TriggerFiredBundle bndle) {
	//		//super(scheduler, bndle);
	//	}

	private void cleanupUserTransaction() {
		if (ut != null) {
			UserTransactionHelper.returnUserTransaction(ut);
			ut = null;
		}
	}

	//@Override
	protected void begin() throws SchedulerException {
		// Don't get a new UserTransaction w/o making sure we cleaned up the old 
		// one.  This is necessary because there are paths through JobRunShell.run()
		// where begin() can be called multiple times w/o complete being called in
		// between.
		cleanupUserTransaction();

		boolean beganSuccessfully = false;
		try {
			log.debug("Looking up UserTransaction.");
			ut = UserTransactionHelper.lookupUserTransaction();

			log.debug("Beginning UserTransaction.");
			ut.begin();

			beganSuccessfully = true;
		} catch (SchedulerException se) {
			throw se;
		} catch (Exception nse) {

			throw new SchedulerException("JTAJobRunShell could not start UserTransaction.", nse);
		} finally {
			if (beganSuccessfully == false) {
				cleanupUserTransaction();
			}
		}
	}

	//@Override
	protected void complete(boolean successfulExecution) throws SchedulerException {
		if (ut == null) {
			return;
		}

		try {
			try {
				if (ut.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
					log.debug("UserTransaction marked for rollback only.");
					successfulExecution = false;
				}
			} catch (SystemException e) {
				throw new SchedulerException("JTAJobRunShell could not read UserTransaction status.", e);
			}

			if (successfulExecution) {
				try {
					log.debug("Committing UserTransaction.");
					ut.commit();
				} catch (Exception nse) {
					throw new SchedulerException("JTAJobRunShell could not commit UserTransaction.", nse);
				}
			} else {
				try {
					log.debug("Rolling-back UserTransaction.");
					ut.rollback();
				} catch (Exception nse) {
					throw new SchedulerException("JTAJobRunShell could not rollback UserTransaction.", nse);
				}
			}
		} finally {
			cleanupUserTransaction();
		}
	}

	/**
	 * Override passivate() to ensure we always cleanup the UserTransaction. 
	 */
	//@Override
	public void passivate() {
		cleanupUserTransaction();
		//super.passivate();
	}
}